package com.kayak.tg.client.utils;

import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ReferenceConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.kayak.distribute.service.IRpcTGService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @ClassName DubboFactory
 * @Dsecription Dubbo服务工厂
 * 一个dubbo服务要素有：zookeeper服务注册地址（address）、分组（group）、版本号（version）、实现接口（interface）。
 * 换言之,（address/group/version/interface）这四个要素确定一个唯一的dubbo服务。
 * @Auth tinxi
 * @DATAE 2019/3/26 15:00
 */
public class DubboFactory {

	private static Logger logger = LoggerFactory.getLogger(DubboFactory.class);

	/**
	 * zk注册中心地址
	 */
	private static String ZK_ADDRESS = "zookeeper://127.0.0.1:2181";

	/**
	 * 服务版本号
	 */
	private static String IMPL_VERSION;

	/**
	 * 当前应用的信息
	 */
	private static ApplicationConfig application = new ApplicationConfig();
	/**
	 * 注册中心信息缓存
	 */
	private static Map<String, RegistryConfig> registryConfigCache = new ConcurrentHashMap<>();
	/**
	 * 各个业务方的ReferenceConfig缓存
	 */
	private static Map<String, ReferenceConfig<IRpcTGService>> referenceCache = new ConcurrentHashMap<>();

	static {
		application.setName("dubbo-factory");
	}

	/**
	 * 获取注册中心信息
	 * @param address zk注册地市
	 * @param group   dubbo服务所在组
	 * @param version
	 * @return
	 */
	private static RegistryConfig getRegistryConfig(String address, String group, String version) {
		String key = address + "-" + group + "-" + version;
		RegistryConfig registryConfig = registryConfigCache.get(key);
		if (null == registryConfig) {
			registryConfig = new RegistryConfig();
			registryConfig.setAddress(address);
			// registryConfig.setGroup(group);

			registryConfigCache.put(key, registryConfig);
		}
		return registryConfig;
	}

	/**
	 * 获取服务的代理对象
	 * @param address
	 * @param group
	 * @param version
	 * @return
	 */
	private static ReferenceConfig<IRpcTGService> getReferenceConfig(Class clazz, String address, String group, String version) {
		String referenceKey = address + "-" + group + "-" + version;
		ReferenceConfig<IRpcTGService> referenceConfig = referenceCache.get(referenceKey);
		if (null == referenceConfig) {

			referenceConfig = new ReferenceConfig<>();
			referenceConfig.setApplication(application);
			referenceConfig.setRegistry(getRegistryConfig(address, group, version));
			referenceConfig.setInterface(clazz);
			referenceConfig.setVersion(version);
			referenceConfig.setGroup(group);
			// referenceConfig.setStub("com.kayak.tg.client.utils.RpcTGServiceStub"); // 设置本地存根
			// referenceConfig.setStub("com.kayak.distribute.service.impl.RpcTGServiceImpl"); // 设置本地存根

			referenceCache.put(referenceKey, referenceConfig);
		}
		return referenceConfig;
	}

	/**
	 * 初始化数据
	 * @param business
	 * @param address
	 * @param group
	 * @param version
	 */
	public static void init(String business, String address, String group, String version) {
		// getReferenceConfig(address, group, version);
	}

	/**
	 * 调用远程服务
	 * 删除business 代表dubbo服务代理对象存在缓存里的key
	 * @param clazz 代理对象的接口
	 * @param address zk注册地址
	 * @param group 分组
	 * @param version 版本
	 * @throws Throwable
	 */
	public static void invoke(Class clazz, String address, String group, String version){
		IRpcTGService proxy = getProxy(clazz, address, group, version);
		if (null != proxy) {
			proxy.rpcInvoke(); // 调用远程服务
		}
	}

	/**
	 * 从注册重新获取服务代理对象
	 * @param clazz
	 * @param address zk注册地址
	 * @param group 分组
	 * @param version 版本
	 * @return
	 */
	public static IRpcTGService getProxy(Class clazz, String address, String group, String version) {
		ReferenceConfig<IRpcTGService> reference = getReferenceConfig(clazz, address, group, version);
		if (null != reference) {
			IRpcTGService iRpcTGService = null;
			try {
				iRpcTGService = reference.get();
			} catch (IllegalStateException e) {
				e.printStackTrace();
				String message = e.getMessage();
				if (message.indexOf("Failed to check the status of the service") != -1
				    && message.indexOf("No provider available for the service") != -1) {
					logger.info(message);
					logger.info("注册中心未找到相应的服务!");
				}
			}
			return iRpcTGService;
		}
		return null;
	}

	/**
	 * 动态获取服务方式
	 * clazz    在本项目中为固定值,
	 * address  也为固定值
	 * gruop    用于获取对应的实现,当一个接口有多个实现，可以用分组区分
	 * version  服务版本号, 建议使用默认版本(null), 当接口存在不兼容则需要使用版本号进行区分
	 * @param args
	 */
	public static void main(String[] args) {
		DubboFactory.invoke(IRpcTGService.class,ZK_ADDRESS,"1",null);
	}
}
